//
// Created by Administrator on 2021/9/28.
//

#include "Matrix4x4.h"


Matrix4x4::Matrix4x4() : MatrixN(4,4) {
}

Matrix4x4 Matrix4x4::operator*(const Matrix4x4 &m) const {
    return Matrix4x4::multiply(*this, m);
}

/**
 * 乘法
 * @param m1 矩阵1
 * @param m2 矩阵2
 * @return
 */
Matrix4x4 Matrix4x4::multiply(const Matrix4x4& m1, const Matrix4x4& m2) {
    HelloAssert::check(m1.col == m2.row, "矩阵行->列不一致,无法相乘");

    Matrix4x4 r;
    for(int i = 0; i < m1.row; i++){
        for(int k = 0; k < m1.col; k++){
            float sum = 0.0f;
            for(int j = 0; j < m2.row; j++){
                float m1r = m1.data[i * m1.row + j];
                float m2c = m2.data[j * m2.row + k];
                sum += m1r * m2c;
            }
            r.data[i * m1.row + k] = sum;
        }
    }

    log_info("multiply r:%s", r.toString().c_str());
    return r;
}

/**
 * 平移变换
 * @return 变换矩阵
 */
Matrix4x4 Matrix4x4::translation(const Matrix4x4& m, const Vector3& v) {
    Matrix4x4 t;
    t.data = {
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        v.x, v.y, v.z, 1
    };
    return m * t;
}

/**
 * 旋转变换
 * @return 旋转矩阵
 */
Matrix4x4 Matrix4x4::rotation(const Matrix4x4& m, float rad, const Vector3& v) {
    if(rad == 0) return m;
    Matrix4x4 t;
    float c = cos(rad);
    float s = sin(rad);
    if(v.x > 0){
        t.data = {
            1, 0, 0, 0,
            0, c, s, 0,
            0, -s, c, 0,
            0, 0,  0, 1
        };
    }else if(v.y > 0){
        t.data = {
                c, 0, -s, 0,
                0, 1, 0, 0,
                -s, 0, c, 0,
                0, 0,  0, 1
        };
    }else if(v.z > 0){
        t.data = {
                c, s, 0, 0,
                -s, c, 0, 0,
                0, 0, 1, 0,
                0, 0,  0, 1
        };
    }else {
        throw HelloException("只支持围绕单一轴旋转");
    }
    return m * t;
}

/**
 * 缩放变换
 * @return 缩放矩阵
 */
Matrix4x4 Matrix4x4::scale(const Matrix4x4& m, const Vector3& v) {
    Matrix4x4 t;
    t.data = {
        v.x, 0, 0, 0,
        0, v.y, 0, 0,
        0, 0, v.z, 0,
        0, 0,   0, 1,
    };
    return m * t;
}

/**
 * 正交投影
 * @param left 左
 * @param right 右
 * @param bottom 下
 * @param top 上
 * @param near 近
 * @param far 远
 * @return 投影矩阵
 *
 */
Matrix4x4 Matrix4x4::orthographic(float left, float right, float bottom, float top, float near, float far) {
    Matrix4x4 r;
    r.data = {
            2 / (right - left), 0, 0, 0,
            0, 2 / (top - bottom), 0, 0,
            0, 0, -2 / far - near, 0,
            -(right + left) / (right - left), -(top + bottom) / (top - bottom), -(far + near) / (far - near), 1
    };
    return r;
}

/**
 * 透视矩阵
 * @param radfov 视野角度
 * @param aspect 宽高比
 * @param near 近
 * @param far 远
 * @return 投影矩阵
|2.41421, 0, 0, 0|
|0, 2.41421, 0, 0|
|0, 0, -1.002, -1|
|0, 0, -2.002, 0|
 */
Matrix4x4 Matrix4x4::perspective(float radfov, float aspect, float near, float far) {
    float fovtanHalf = tan(radfov / 2.0);
    Matrix4x4 r;
    r.data = {
        1 / (aspect * fovtanHalf), 0, 0, 0,
        0, 1 / fovtanHalf, 0, 0,
        0, 0, -(far + near) / (far - near), -1,
        0, 0, -(2 * far * near) / (far - near), 0,
    };
    return r;
}


